home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
video
/
pictetri.src
/
pictetri
/
pictetris-src
/
game.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-19
|
11KB
|
337 lines
/***************************************************************************\
|* *|
|* game.c: A version of Tetris to run on Linux SVGAlib console. *|
|* This is the module that actually plays the game. *|
|* *|
|* Authors: Mike Taylor (mirk@uk.ac.warwick.cs) & *|
|* Arturo Espinosa (arturo@nuclecu.unam.mx) *|
|* Started: Fri May 26 12:26:05 BST 1989 (tetris for terminals) *|
|* Dic 1, 1995 (pictetris) *|
|* *|
\***************************************************************************/
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <errno.h>
/* Here's what is need for this under Linux */
void l_usleep (unsigned long usec)
{
struct timeval timeout;
timeout.tv_sec = usec / 1000000;
timeout.tv_usec = usec - 1000000 * timeout.tv_sec;
select (1, NULL, NULL, NULL, &timeout);
}
#include "pictetris.h"
#include "game.h"
#include "screen.h"
#include "pieces.h"
#include "utils.h"
/*-------------------------------------------------------------------------*/
extern long int random ();
extern int rand_lines; /* Garbage lines at the start of the game */
extern int piece_no_next; /* The next piece to appear... */
extern int orient_next; /* next piece orientation */
extern int next_box; /* Flag for the next-piece box */
extern int sound; /* Sound flag */
extern int total_time;
/*-------------------------------------------------------------------------*/
char left_key = LEFT_KEY; /* Move piece left */
char right_key = RIGHT_KEY; /* Move piece right */
char rotate_key = ROTATE_KEY; /* Rotate piece anticlockwise */
char drop_key = DROP_KEY; /* Drop piece to bottom of screen */
char susp_key = SUSP_KEY; /* Suspend. I'm sorry if its confusing */
char quit_key = QUIT_KEY; /* Quit. I'm sorry if its confusing */
int piece_no_next; /* The next piece to appear... */
int orient_next; /* next piece orientation */
/***************************************************************************\
|* *|
|* Oh good grief, what on earth is the point of putting a huge, wobbly *|
|* box-comment in front of this titchy little self-explanatory function? *|
|* The name tells the whole story, it's perfectly strightforward, it's *|
|* not a proposition from Witgenstein. I wouldn't bother commenting it *|
|* at all if it wasn't for the fact that I know I'd feel guilty in the *|
|* morning. I mean, be fair, you don't really want a program where all *|
|* the functions *except one* have box-comments explaining them, do you? *|
|* Ah well, here we go for completion's sake: *|
|* *|
|* The function clear_board() takes no parameters and returns no value. *|
|* It clears the board. The end. *|
|* *|
\***************************************************************************/
void clear_board ()
{
int i, j;
for (i = 0; i < GAME_DEPTH+4; i++)
for (j = 0; j < GAME_WIDTH; j++)
board[i][j] = PI_EMPTY;
}
/***************************************************************************\
|* *|
|* The function play_game is the main loop in which the game of Tetris *|
|* is implemented. It takes no parameters, and returns no value. The *|
|* time at which it returns no value is the end of a game. The main *|
|* loop-component is a select(2) which polls the keyboard in real-time. *|
|* If you use a non-Berkeley UNIX(tm), you're well cheesed. *|
|* *|
|* Actually, I have to admit I'm not proud of this one. It must be one *|
|* of the messiest functions I've written in years, in terms of nested *|
|* loops with ad-hoc exit conditions, re-used variables, general *|
|* obfuscation and so on. I wanna make it quite clear that I make no *|
|* apologies for my use of "goto", which remains a highly desirable *|
|* language feature, and is still the most elegant way of coding many *|
|* things, but I gotta admit, overall this one is bit of a chicken. *|
|* *|
\***************************************************************************/
void play_game ()
{
int i; /* Position of origin down board */
int j; /* Position of origin across board */
int k; /* Loop variable when i,j are invariant */
int l; /* Yet another loop variable... */
int piece_no; /* Type of piece currently falling */
int orient; /* Which way it is facing */
int pause_flag = 0; /* We won't pause unless told to */
int presses_left; /* Futher moves possible this drop */
int free_left = game_level; /* Number of pieces to drop at start */
fd_set read_fds; /* Select must look at stdin */
int time_passed; /* Counts the time it has passed */
int sel_impostor = 0; /* fake select... couldn't do it other way */
int dif_levels; /* new scoring: more levels score better */
struct timeval timeout; /* Time before piece drops in select(2) */
char ch; /* Keystroke (command) */
score = no_levels = no_pieces = 0;
update_scores ();
clear_board ();
for(i=19;i>19-rand_lines;i--)
for(j=0;j<10;j++) /* Place garbage lines */
board[i+4][j]=(PI_EMPTY * (int) (random() % 2));
draw_board();
piece_no = (int) (random () % NO_PIECES); /* Pick the first piece to */
orient = (int) (random () % NO_ORIENTS); /* appear. */
while (1) {
piece_no_next = (int) (random () % NO_PIECES); /* Pick the next piece */
orient_next = (int) (random () % NO_ORIENTS); /* each time */
if (next_box) draw_next_piece_box(piece_no_next,orient_next);
i = -2; /* Start falling from off-screen */
if (free_left > 0) /* If we have random starting-pieces */
j = 1 + (int) (random () % (GAME_WIDTH-2));
else /* places them randomly, otherwise */
j = GAME_WIDTH/2; /* put the piece in the middle */
if (!can_place (piece_no, orient, i, j)) {
for (k = 0; k < 9; k++) { /* Crude but (hopefully) effective */
draw_piece (piece_no, orient, i, j, PD_ERASE);
myrefresh (); l_usleep (80000);
draw_piece (piece_no, orient, i, j, PD_DRAW);
myrefresh (); l_usleep (80000);
}
break; /* End of game - piece won't fit */
}
if (free_left != 0) { /* If there are pieces to be dropped, */
if (free_left > 0) /* And the number is positiive, */
free_left--; /* Then decrement it, otherwise */
else /* increment it, in any case, bring */
free_left++; /* it closer to zero if it gets to zero */
if (free_left == 0) /* set a flag so that the game will */
pause_flag = 1; /* pause. Then go to the bit of code */
goto DROP_PIECE; /* that drops it. */
}
while (1) {
presses_left = NO_MOVES;
draw_piece (piece_no, orient, i, j, PD_DRAW);
update_scores ();
myrefresh ();
while (1) {
check_pic_change();
do {
sel_impostor=0;
l_usleep(2000);
if (scan_key(quit_key)) sel_impostor=quit_key;
if (scan_key(susp_key)) sel_impostor=susp_key;
if (scan_key(DOWN_KEY)) time_passed=total_time/2000;
if (scan_key(drop_key)) sel_impostor=drop_key;
if (scan_key(rotate_key)) sel_impostor=rotate_key;
if (scan_key(left_key)) sel_impostor=left_key;
if (scan_key(right_key)) sel_impostor=right_key;
time_passed++;
flush_keyboard();
} while ((time_passed<total_time/2000)&&(sel_impostor==0));
if (time_passed>=total_time/2000) time_passed=0;
switch (sel_impostor) {
case 0:
goto TIMEOUT;
default:
ch=sel_impostor;
if (ch == REFRESH_KEY)
hoopy_refresh ();
if ((ch != left_key) && (ch != right_key) && (ch != rotate_key) &&
(ch != drop_key) && (ch != quit_key) && (ch != susp_key))
break;
presses_left--;
if (ch == left_key) {
if (can_place (piece_no, orient, i, j-1)) {
draw_piece (piece_no, orient, i, j, PD_ERASE);
j--;
draw_piece (piece_no, orient, i, j, PD_DRAW);
myrefresh ();
}
}
else if (ch == right_key) {
if (can_place (piece_no, orient, i, j+1)) {
draw_piece (piece_no, orient, i, j, PD_ERASE);
j++;
draw_piece (piece_no, orient, i, j, PD_DRAW);
myrefresh ();
}
}
else if (ch == rotate_key) {
int new_or = ((rotate_backwards == 0) ? ((orient+1)%NO_ORIENTS) :
((orient-1)%NO_ORIENTS+NO_ORIENTS*(orient == 0)));
if (can_place (piece_no, new_or, i, j)) {
draw_piece (piece_no, orient, i, j, PD_ERASE);
orient = new_or;
draw_piece (piece_no, orient, i, j, PD_DRAW);
myrefresh ();
}
}
else if (ch == drop_key) {
DROP_PIECE:
while (can_place (piece_no, orient, i+1, j)) {
draw_piece (piece_no, orient, i, j, PD_ERASE);
i++;
draw_piece (piece_no, orient, i, j, PD_DRAW);
myrefresh ();
}
goto TIMEOUT;
}
else if (ch == quit_key)
return;
else if (ch == susp_key) {
print_msg ("Paused");
flush_keyboard();
get_keyboard_key();
draw_area();
hoopy_refresh();
}
break;
}
}
TIMEOUT:
if (!can_place (piece_no, orient, i+1, j)) {
place_piece (piece_no, orient, i, j);
score += pieces[piece_no].points;
no_pieces++;
update_scores ();
myrefresh ();
dif_levels=no_levels;
for (i = 0; i < GAME_DEPTH; i++) {
for (j = 0; j < GAME_WIDTH; j++)
if (board[i+4][j] == PI_EMPTY)
break;
if (j == GAME_WIDTH) {
no_levels++;
for (l=0;l<2;l++) {
for (k=0;k<GAME_WIDTH;k++)
board[i+4][k]=PI_EMPTY;
draw_board();
myrefresh();
l_usleep(2500);
if (sound) {
printf("\7");
fflush(stdout);
}
for (k=0;k<GAME_WIDTH;k++)
board[i+4][k]=4;
draw_board();
myrefresh();
l_usleep(2500);
if (sound) {
printf("\7");
fflush(stdout);
}
}
for (k = i; k > 0; k--)
for (j = 0; j < GAME_WIDTH; j++)
board[k+4][j] = board[k+3][j];
for (j = 0; j < GAME_WIDTH; j++)
board[4][j] = PI_EMPTY;
draw_board ();
myrefresh ();
i--; /* Check the new row i */
}
}
switch (no_levels-dif_levels) {
case 0: break;
case 4: score+=40;
case 3: score+=30;
case 2: score+=20;
case 1: score+=10;
update_scores();
myrefresh();
}
if (pause_flag) { /* If we are pausing after this drop ... */
pause_flag = 0; /* Ensure we don't do so next time. */
draw_area();
hoopy_refresh();
}
break; /* End of fall - piece has hit floor */
}
draw_piece (piece_no, orient, i, j, PD_ERASE);
i++;
}
piece_no=piece_no_next; /* Now the current piece is the one you */
orient=orient_next; /* promised it would be. */
if (total_time != 0) /* This increases the difficulty level */
total_time -= 100; /* (he, he, he... :) */
}
}
/*-------------------------------------------------------------------------*/